#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char * readline(FILE *fp);
void readchar(FILE *fp);

int main() {
  // FILE *fopen(const char *filename, const char *mode); 失败返回 NULL；
  /*
  r：只读；文件不存在，失败；
  r+：读写；文件不存在，失败；
  w：只写（覆盖写）；文件不存在，创建新文件；
  w+：覆盖写打开可读；文件不存在，创建新文件；
  a：追加写；文件不存在，创建新文件；
  a+：追加写打开可读；文件不存在，创建新文件。
  rb，rb+，wb，wb+，ab，ab+，都是二进制文件。
   */
  
  // 两个预定义宏
  // __FILE__
  // __LINE__

  // int fclose(FILE *fp);
  // long ftell(FILE *); 返回当前文件的游标位置；
  // int fseek(FILE *, long offset, int whence); 0 成功，负数失败；
  //    参数3有三个值：
  //      SEEK_SET：文件头开始；此时参数2应该是 >= 0 的；
  //      SEEK_CUR：当前文件的游标位置；此时参数2 如果是 >= 0 的，则向后偏移，如果是 <= 0 的，则向前偏移；
  //      SEEK_END：文件尾位置；此时参数2应该是 <= 0 的；

  // FILE * fp = fopen("a.txt", "r");
  // fseek(fp, 0, SEEK_END);
  // int len = ftell(fp);// 回车也计算在内，并且windows中\r\n是两个字符，也就是2个字节。
  // printf("%d\n", len);
  // fclose(fp);




  // int fgetc(FILE *fp);返回所读取到的字符的ASCII码值；
  // int fputc(int c, FILE *fp); c 要写入的字符的ASCII码值，成功返回c，失败返回-1；
  // 
  // int fputs(const char *str, FILE *fp);
  // char * fgets(char *outstr, int size, FILE *fp);
  //    成功返回 outstr 的首地址，失败返回 NULL；
  //    最多读取一行，也就是说，假如第一个行50个字节，但size指定为100，则只会把第一行读出来，不会跨行读取；
  //    size-1 这个是读取后的游标位置；
  //    \n 一起读。


  // 逐个读取字符
  // FILE *fp = NULL;
  // fp = fopen("a.txt", "r");
  // readchar(fp);
  // readchar(fp);
  // readchar(fp);
  // readchar(fp);


  // 逐行读取一个文件的内容
  // FILE *fp = NULL;
  // char *p = NULL;
  // fp = fopen("a.txt", "r");
  // if (fp == NULL) {
  //   printf("Error open file failed in %s at %d\n", __FILE__, __LINE__);
  // } else {
  //   p = readline(fp);
  //   while(p != NULL) {
  //     printf("%s", p);
  //     // free(p);
  //     p = readline(fp);
  //   }
  //   fclose(fp);
  //   printf("\n%s\n", "hehe");
  // }


  // 格式化读写
  // int fprintf(FILE *fp, const char *format, ...); 格式化后写入文件中；
  // int fscanf(FILE *fp, const char *format, ...); 从文件中按格式化写入到变量中；到空格就结束了。


  // int fread(void *ptr, int size, int nmemb, FILE *fp);size 每个元素占多少字节； nmemb 希望读取多少个元素；返回值 实际读取的字节数；
  // int fwrite(void *ptr, int size, int nmemb, FILE *fp);

  FILE *fp = NULL;
  int w = 0;
  int h = 0;
  fp = fopen("78917228215594.bmp", "rb");
  if (NULL == fp) {
    printf("Error open file failed in %s at %d\n", __FILE__, __LINE__);
  } else {
    fseek(fp, 18, SEEK_SET);
    // F0 00 00 00
    // 40 01 00 00
    // 第一个是：00 00 00 F0 结果是 15 * 16 = 240；
    // 第二个是：00 00 01 40 结果是 1 * 16^2 + 4 * 16^1 = 256 + 64 = 320；
    fread(&w, sizeof(int), 1, fp);
    fread(&h, sizeof(int), 1, fp);
    fclose(fp);
    printf("%d\n", w);
    printf("%d\n", h);
  }

  return EXIT_SUCCESS;
}


// 读取一个字符
// 多次执行，每次都继续往后读取，这就是下面的逐行读取成功的原因。
void readchar(FILE *fp) {
  int ch = fgetc(fp);
  printf("%c\n", ch);
}


// 读取一行
char * readline(FILE *fp) {
  // 当前游标
  int curr = 0;
  // 请求内存的总字节数
  int count = 0;
  // 读取字节的ASCII码值
  int ch = 0;
  
  char *pout = NULL;
  char *pret = NULL;
  
  if (fp == NULL) {
    printf("Error input parameter invalid in %s at %d\n", __FILE__, __LINE__);
    return NULL;
  }
  curr = ftell(fp);

  ch = fgetc(fp);
  // printf("\n\n");
  // printf("%d\n", ch);
  // printf("\n\n");
  while(ch != 'n' && ch >= 0) {
    count++;
    ch = fgetc(fp);
  }
  count += 2; // 包含\n，并且添加一个 '\0';

  pout = (char *)malloc(count);
  if (pout == NULL) {
    printf("Error malloc failed in %s at %d\n", __FILE__, __LINE__);
    fseek(fp, curr, SEEK_SET);
    return NULL;
  }
  memset(pout, 0, count);// 所有字节重置为0，这样也保证了最后一个字符是0，也就是'\0'，使得字符串完整终结。

  fseek(fp, curr, SEEK_SET);
  pret = fgets(pout, count, fp);
  if (pret == NULL) {
    free(pout);
    return NULL;
  } else {
    return pout;
  }
}